package com.leyou.order.service;

import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.IdWorker;
import com.leyou.common.utils.UserHolder;
import com.leyou.item.clients.ItemClient;
import com.leyou.item.dto.SkuDTO;
import com.leyou.order.dto.CartDTO;
import com.leyou.order.dto.OrderDTO;
import com.leyou.order.entity.Order;
import com.leyou.order.entity.OrderDetail;
import com.leyou.order.entity.OrderLogistics;
import com.leyou.order.entity.enums.OrderStatusEnum;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderLogisticsMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.utils.PayHelper;
import com.leyou.order.vo.OrderDetailVO;
import com.leyou.order.vo.OrderLogisticsVO;
import com.leyou.order.vo.OrderVO;
import com.leyou.user.clients.UserClient;
import com.leyou.user.dto.AddressDTO;
import feign.FeignException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;

/**
 * @author 虎哥
 */
@Slf4j
@Service
public class OrderService {

    private final OrderMapper orderMapper;
    private final OrderDetailMapper detailMapper;
    private final OrderLogisticsMapper logisticsMapper;
    private final IdWorker idWorker;
    private final ItemClient itemClient;
    private final UserClient userClient;
    private final PayHelper payHelper;

    public OrderService(OrderMapper orderMapper, OrderDetailMapper detailMapper, OrderLogisticsMapper logisticsMapper, IdWorker idWorker, ItemClient itemClient, UserClient userClient, PayHelper payHelper) {
        this.orderMapper = orderMapper;
        this.detailMapper = detailMapper;
        this.logisticsMapper = logisticsMapper;
        this.idWorker = idWorker;
        this.itemClient = itemClient;
        this.userClient = userClient;
        this.payHelper = payHelper;
    }

    @Transactional
    public Long createOrder(OrderDTO orderDTO) {
        // 1.订单
        Order order = new Order();
        // 1.1.订单id
        long orderId = idWorker.nextId();
        order.setOrderId(orderId);
        // 1.2.订单金额
        // 1.2.1.获取购物车信息
        List<CartDTO> carts = orderDTO.getCarts();
        // 1.2.2.获取商品id集合
        Map<Long, Integer> skuMap = new HashMap<>();
        for (CartDTO cart : carts) {
            skuMap.put(cart.getSkuId(), cart.getNum());
        }
        // Map<Long, Integer> skuMap = carts.stream().collect(Collectors.toMap(CartDTO::getSkuId, CartDTO::getNum));
        Set<Long> ids = skuMap.keySet();
        List<Long> idList = new ArrayList<>(ids);
        // 1.2.3.查询sku
        List<SkuDTO> skuList = itemClient.querySkuByIds(idList);
        // 1.2.4.计算总金额
        long total = 0L;
        for (SkuDTO sku : skuList) {
            // 获取商品的购买数量
            Integer num = skuMap.get(sku.getId());
            total += sku.getPrice() * num;
        }
        // 商品总金额
        order.setTotalFee(total);
        // 邮费，全场包邮
        order.setPostFee(0L);
        // 实付金额：总金额 + 邮费 - 优惠金额
        order.setActualFee(order.getTotalFee() + order.getPostFee());
        order.setPaymentType(orderDTO.getPaymentType());

        // 1.3.用户
        Long userId = UserHolder.getUserInfo().getId();
        order.setUserId(userId);
        // 1.4.订单状态
        order.setStatus(OrderStatusEnum.INIT.value());
        // 1.5.写数据库
        orderMapper.insertSelective(order);

        // 2.订单详情 CartDTO --> skuId --> sku对象 --> OrderDetail
        // 2.1.准备OrderDetail集合
//        List<OrderDetail> detailList = skuList.stream()
//                .map(s -> this.getOrderDetail(orderId, skuMap, s)).collect(Collectors.toList());
        List<OrderDetail> detailList = new ArrayList<>();
        for (SkuDTO sku : skuList) {
            // 2.2.把sku数据封装到OrderDetail
            OrderDetail detail = getOrderDetail(orderId, skuMap, sku);
            detailList.add(detail);
        }
        // 2.3.写数据库
        detailMapper.insertList(detailList);

        // 3.订单物流 tb_order_logistics
        // 3.1.获取地址id
        Long addressId = orderDTO.getAddressId();
        // 3.2.根据地址去user-service查询地址信息
        AddressDTO address = userClient.queryAddressById(userId, addressId);
        // 3.3.把查询的地址信息封装成OrderLogistics
        OrderLogistics logistics = BeanHelper.copyProperties(address, OrderLogistics.class);
        logistics.setOrderId(orderId);
        // 3.4.写入数据库
        logisticsMapper.insertSelective(logistics);

        // 4.扣减库存
        try {
            itemClient.deductStock(skuMap);
        } catch (FeignException e) {
            // 扣减库存失败，抛出异常
            throw new RuntimeException(e.contentUTF8());
        }

        // TODO 5.删除购物车商品

        return orderId;
    }

    private OrderDetail getOrderDetail(long orderId, Map<Long, Integer> skuMap, SkuDTO sku) {
        OrderDetail detail = new OrderDetail();
        detail.setTitle(sku.getTitle());
        detail.setSkuId(sku.getId());
        detail.setPrice(sku.getPrice());
        detail.setNum(skuMap.get(sku.getId()));
        detail.setOwnSpec(sku.getOwnSpec());
        detail.setImage(StringUtils.substringBefore(sku.getImages(), ","));
        detail.setOrderId(orderId);
        return detail;
    }

    public OrderVO queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (order == null) {
            throw new LyException(ExceptionEnum.DATA_NOT_FOUND);
        }
        OrderVO orderVO = BeanHelper.copyProperties(order, OrderVO.class);
        // 2.查询订单详情
        orderVO.setDetailList(queryDetailByOrderId(orderId));
        // 3.查询物流
        orderVO.setLogistics(queryLogisticsByOrderId(orderId));
        return orderVO;
    }

    private OrderLogisticsVO queryLogisticsByOrderId(Long orderId) {
        OrderLogistics logistics = logisticsMapper.selectByPrimaryKey(orderId);
        if (logistics == null) {
            throw new LyException(ExceptionEnum.DATA_NOT_FOUND);
        }
        return BeanHelper.copyProperties(logistics, OrderLogisticsVO.class);
    }

    private List<OrderDetailVO> queryDetailByOrderId(Long orderId) {
        OrderDetail detail = new OrderDetail();
        detail.setOrderId(orderId);
        List<OrderDetail> list = detailMapper.select(detail);

        if (CollectionUtils.isEmpty(list)) {
            throw new LyException(ExceptionEnum.DATA_NOT_FOUND);
        }
        return BeanHelper.copyWithCollection(list, OrderDetailVO.class);
    }

    public String getPayUrl(Long orderId) {
        // 查询订单
        Order order = orderMapper.selectByPrimaryKey(orderId);
        // 健壮性处理
        if (order == null) {
            // 订单不存在，订单id不对
            throw new LyException(ExceptionEnum.REQUEST_PARAM_ERROR);
        }
        // 订单状态
        Integer status = order.getStatus();
        if (!status.equals(OrderStatusEnum.INIT.value())) {
            // 已经付款或关闭，无需支付了
            throw new RuntimeException("订单已经支付或关闭！");
        }
        // 获取订单金额
        Long actualFee = order.getActualFee();
        // 获取商品信息
        OrderDetail detail = new OrderDetail();
        detail.setOrderId(orderId);
        List<OrderDetail> details = detailMapper.select(detail);
        String desc = "乐优商城商品: 【" + details.get(0).getTitle() + "】";
        return payHelper.getPayUrl(desc, orderId, actualFee);
    }

    @Transactional
    public void handleNotify(Map<String, String> data) {
        // 1.业务校验
        payHelper.checkResultCode(data);
        // 2.签名校验
        payHelper.checkSignature(data);
        // 3.金额校验
        // 3.1.获取支付金额
        String totalFee = data.get("total_fee");
        // 3.2.获取数据库的订单金额
        // 3.2.1.获取订单id
        String outTradeNo = data.get("out_trade_no");
        if (StringUtils.isBlank(totalFee) || StringUtils.isBlank(outTradeNo)) {
            // 数据有误
            throw new RuntimeException("数据有误");
        }
        Long orderId = Long.valueOf(outTradeNo);
        // 3.2.2.查询订单
        Order order = orderMapper.selectByPrimaryKey(orderId);
        // 3.3.比较金额
        if (!totalFee.equals(order.getActualFee().toString())) {
            // 金额有误，非法数据
            throw new RuntimeException("数据有误，再捣乱我就报警了！");
        }

        // 4.幂等校验
        if (!order.getStatus().equals(OrderStatusEnum.INIT.value())) {
            // 订单不是未支付，说明订单已经处理过了
            log.info("微信支付的重复通知，订单{}已经处理过了。", orderId);
            return;
        }

        // 5.修改订单状态 update tb_order set status = 2 where order_id = 123124 and status = 1

        // set status = 2 , pay_time = NOW()
        Order record = new Order();
        record.setStatus(OrderStatusEnum.PAY_UP.value());
        record.setPayTime(new Date());
        // where order_id = 123124 and status = 1
        Example example = new Example(Order.class);
        example.createCriteria()
                .andEqualTo("orderId", orderId)
                .andEqualTo("status", OrderStatusEnum.INIT.value());

        int count = orderMapper.updateByExampleSelective(record, example);
        if(count == 0){
            // 更新失败
            return;
        }

        log.info("微信支付通知成功处理！订单id：{}", orderId);

        // TODO 6.发短信通知用户

        // TODO 7.通知仓储服务，应该发货
    }

    public Integer queryOrderState(Long orderId) {
        // 查询订单
        Order order = orderMapper.selectByPrimaryKey(orderId);
        // 非空判断
        if (order == null) {
            throw new LyException(ExceptionEnum.DATA_NOT_FOUND);
        }
        // 返回状态
        return order.getStatus();
    }
}
